package com.andy.myFramework.mvc;

import com.andy.myFramework.mvc.annotation.Controller;
import com.andy.myFramework.mvc.annotation.RequestMapping;
import com.andy.myFramework.mvc.annotation.Security;
import com.andy.myFramework.mvc.pojo.Handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DefaultHandlerFactory implements HandlerFactory {

    //管理handler的列表
    private List<Handler> handlerMapping = new ArrayList<>();

    /**
     * 获取一个handler
     * @param url
     * @return
     */
    @Override
    public Handler getHandle(String url) {
        for (Handler handler : handlerMapping) {
            Matcher matcher = handler.getPattern().matcher(url);
            if(matcher.matches()) return handler;
        }
        return null;
    }


    /**
     * 初始化handler容器
     * @param singletons ioc单例池
     */
    @Override
    public void initHandlerFactory(Map<String,Object> singletons) {
        //循环单例池 处理controller注解
        for (Map.Entry<String, Object> entry : singletons.entrySet()) {
            Object controllerBean = entry.getValue();
            Class controllerClass = controllerBean.getClass();
            //没有controller的注解不处理
            if(!controllerClass.isAnnotationPresent(Controller.class)) continue;
            //处理类上的RequestMapping注解
            String baseUrl = "";
            if(controllerClass.isAnnotationPresent(RequestMapping.class)){
                RequestMapping annotation = (RequestMapping)controllerClass.getAnnotation(RequestMapping.class);
                baseUrl = annotation.value();
            }
            //循环处理method的RequestMapping注解
            Method[] methods = controllerClass.getMethods();
            for (Method method : methods) {
                //方法上没有注解就不处理
                if(!method.isAnnotationPresent(RequestMapping.class)) continue;
                //获取方法上的url
                RequestMapping annotation = method.getAnnotation(RequestMapping.class);
                String methodUrl = annotation.value();
                //拼接得到最终的url
                String url = baseUrl + methodUrl;

                //1-创建基础handler
                Handler handler = new Handler(controllerBean, method, Pattern.compile(url));
                //2-计算方法的参数位置信息
                Parameter[] parameters = method.getParameters();
                for (int j = 0; j < parameters.length; j++) {
                    Parameter parameter = parameters[j];
                    if(parameter.getType() == HttpServletRequest.class || parameter.getType() == HttpServletResponse.class) {
                        // 如果是request和response对象，那么参数名称写HttpServletRequest和HttpServletResponse
                        handler.getParamIndexMapping().put(parameter.getType().getSimpleName(),j);
                    }else{
                        handler.getParamIndexMapping().put(parameter.getName(),j);  // <name,2>
                    }
                }
                //3-security注解权限控制
                //优先使用方法上面的权限控制（因为用户权限无法合并，所以如果方法上设置了就是用方法上，方法上没有设置就是用类上，都没有设置则不控制）
                String securityValue = "";
                if(method.isAnnotationPresent(Security.class)){
                    Security security = method.getAnnotation(Security.class);
                    securityValue = security.value();
                }else if(controllerClass.isAnnotationPresent(Security.class)){
                    Security security = (Security)controllerClass.getAnnotation(Security.class);
                    securityValue = security.value();
                }
                //把字符串拆分，放入set中
                Set<String> securities = new HashSet<>();
                String[] securitySplit = securityValue.split(",");
                for (String s : securitySplit) {
                    securities.add(s);
                }
                handler.setSecurities(securities);

                //last-建立url和method之间的映射关系（map缓存起来）
                handlerMapping.add(handler);
            }
        }
    }


}
